/*
 * Copyright (c) Huawei Device Co., Ltd. 2023. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef SE_SERVICE_H
#define SE_SERVICE_H

#include <mutex>
#include <unordered_map>
#include <vector>

#include "common_utils.h"
#include "isecure_element_service.h"
#include "iremote_object.h"
#include "service_proxy.h"

namespace OHOS {
class IRemoteObject;

namespace SE {
namespace OMAPI {
class Reader;
class ISecureElementReader;

class SEService : public std::enable_shared_from_this<SEService> {
public:

    SEService();
    ~SEService();

    /**
     * @brief Creates the SEService instance.
     * @param initStatus true if the service is created success, false otherwise.
     * @param callback used to notify fwk se service died.
     * @return The status code for function calling.
     */
    using SeServiceDeathCallback = std::function<void()>;
    int InitSEService(bool &initStatus, SeServiceDeathCallback callback);

    /**
     * @brief Checks whether or not the service is connected.
     * @param isConnected True if the service is connected, false otherwise.
     * @return The status code for function calling.
     */
    int IsConnected(bool &isConnected);
    /**
     * @brief Get the list of available SE readers. There must be no duplicated objects in the returned list. All
     * available readers SHALL be listed even if no card is inserted
     * @param readerList The readers list , as an array of readers. If there are no readers,
     * the returned array is of length 0
     * @return The status code for function calling.
     */
    int GetReaders(std::vector<std::shared_ptr<Reader>>& readerList);
    /**
     * @brief Releases all SE resources allocated by this SEService (including any binding to an underlying service). As
     * a result isConnected() will return false after shutdown() was called. After this method call, the SEService
     * object is not connected.
     * @return The status code for function calling.
     */
    int Shutdown(void);
    /**
     * @brief Returns the version of the Open Mobile API Specification this implementation is based on.
     * @param version String containing the Open Mobile API version
     * (e.g. “3.3” for Open Mobile API Specification version 3.3).
     * @return The status code for function calling.
     */
    int GetVersion(std::string& version);

    /**
     * @brief handle load service finished, check the status and create the proxy.
     * @param remoteObject the remote service object.
     * @param success the status to load the remote service.
     */
    void HandleLoadServiceFinished(const sptr<IRemoteObject>& remoteObject, bool success);
    void OnRemoteDied(const wptr<IRemoteObject> &remoteObject);

private:
    class SeServiceDeathRecipient : public IRemoteObject::DeathRecipient {
    public:
        explicit SeServiceDeathRecipient(SEService *client) : client_(client) {}
        ~SeServiceDeathRecipient() override = default;
        void OnRemoteDied(const wptr<IRemoteObject> &remoteObject) override;
    private:
        SEService *client_;
        // mutex used to call the functions by IPC
        std::mutex mutex_{};
    };

private:
    // service interface used for IPC calling.
    sptr<ServiceProxy> serviceProxy_;
    wptr<ISecureElementService> serviceImpl_;

    // mutex used to call the functions by IPC
    std::mutex mutex_{};

    // the reader name and reader interface found.
    std::unordered_map<std::string, std::shared_ptr<Reader>> readers_;

    // flag used to notify the service loaded status.
    bool serviceLoadedReadyFlag_ = false;

    // signal used to notify the sa is loaded finished.
    std::condition_variable seConditionVariable_;

    // seService connect status
    bool isConnected_ {false};

    sptr<IRemoteObject> remote_;
    sptr<IRemoteObject::DeathRecipient> deathRecipient_{};
};
}  // namespace OMAPI
}  // namespace SE
}  // namespace OHOS
#endif // SE_SERVICE_H
